package com.example.filter;

import com.example.pojo.LoginUser;
import com.example.utils.JwtUtil;
import com.example.utils.RedisCache;
import io.jsonwebtoken.Claims;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Objects;
import org.apache.commons.lang3.StringUtils;

/*
 *  @author 雨安
 *  类名： JwtAuthenticationTokenFilter
 *  创建时间：2024/3/20 继承过滤器接口，其他接口可能导致一次请求多次调用
 */
@Component //注入Spring容器当中
public class JwtAuthenticationTokenFilter extends OncePerRequestFilter {

    //装配RedisUtils类
    @Autowired
    private RedisCache redisCache;

    //作用域放大
    private String userid;

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        //获取token 获取前端的指定请求头
        String token = request.getHeader("token");
        //判断请求头携带token
        if (StringUtils.isNotBlank(token) == false){
            //放行，此处既然token没有直接放行
            filterChain.doFilter(request,response);
            //因为后面做的东西都是对token解析什么的他没有所以直接放行避免不必要的资源时间浪费，放行后他会执行后面的过滤器。
            return;
        }
        //解析token
        try{
            //拿到token对象
            Claims claims = JwtUtil.parseJWT(token);
            //获取用户id
            userid = claims.getSubject();
            System.out.println(userid + "eee");
        }catch (Exception e){
            //出现异常抛出
            throw new RuntimeException("解析token失败了,token非法");
        }
        //拿到存入redis的key
        String redisKey = "login:" +userid;
        //从Redis中获取用户信息,此处方法设置了方法泛型会通过我们的调用来进行一个类型窥测从而实现不需要强制类型转换将对象映射实体类
        LoginUser loginUser = redisCache.getCacheObject(redisKey);
        //判断对象是否为null
        if (Objects.isNull(loginUser)){
            throw new RuntimeException("用户未登录");
        };
        //创建Authentication对象, 参数一：账号 参数二：密码 参数三：判断你是否已经认证状态
        //TODO 获取权限信息封装到：Authentication中
        UsernamePasswordAuthenticationToken authenticationToken =
                //第一个：账号密码 第三个：权限信息
                new UsernamePasswordAuthenticationToken(loginUser,null,loginUser.getAuthorities());
        //存入SecurityContextHolder
        SecurityContextHolder.getContext().setAuthentication(authenticationToken);
        //对请求进行放行
        filterChain.doFilter(request,response);
    }


}
